package dyyx;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

// -Xmx4g -Xms4g  -XX:+UnlockExperimentalVMOptions -XX:+UseZGC
public class GCTestMain {

    // 10k
    private static final int VALUE_SIZE = 1024 * 10;
    //
    private static final int MAX_KEY_COUNT = 10000 * 10000;

    private static final Random random = new Random();

    private static final double HEAP_USE_MAX = 0.7;

    public static volatile long lastClearRunTime = -1;
    public static volatile String lastClearRunTimeAt = null;
    public static volatile String lastClearInfo = null;

    // 开始写入 数据 的时间
    public static volatile long runStartTime = -1;

    public static AtomicLong clearRunCount = new AtomicLong(0);
    public static AtomicLong clearRunTotalTime = new AtomicLong(0);

    public static AtomicLong clearCountTotal = new AtomicLong(0);

    public static AtomicLong totalKeyCount = new AtomicLong(0);
    public static AtomicLong errorCount = new AtomicLong(0);
    public static volatile String lastError = null;

    public static final String startTime = LocalDateTime.now().toString();

    public static final Map<String, String> datamap = new ConcurrentHashMap<>();

    private static final int PORT = 8050;

    public static void main(String[] args) throws Exception {

        int port = getPort();
        SimpleHttpServer2.start(port);
        System.out.println("GCTest simple http server start,port=" + port);
        System.out.println("GET request support only");

        new Thread(GCTestMain::run).start();

        JvmPauseMonitor jvmPauseMonitorThread = new JvmPauseMonitor();
        jvmPauseMonitorThread.setName("jvmPauseMonitorThread");
        jvmPauseMonitorThread.start();

    }

    private static final int getPort() {
        int port = PORT;
        try {
            port = Integer.parseInt(System.getProperty("port"));
        } catch (Throwable e) {
            //
        }
        if (port <= 0) {
            port = PORT;
        }
        return port;
    }

    private static final String genKey() {
        totalKeyCount.getAndIncrement();
        return "key-" + random.nextInt(MAX_KEY_COUNT);
    }

    private static final String genValue() {
        StringBuilder sb = new StringBuilder(VALUE_SIZE);
        sb.append(totalKeyCount).append(":");

        sb.append(LocalDateTime.now().toString()).append(":");

        for (int i = 0; i < VALUE_SIZE; i++) {
            sb.append("X");
        }

        return sb.toString();
    }

    private static void doSleep(long sleep) {
        if (sleep <= 0) {
            return;
        }
        try {
            Thread.sleep(sleep);
        } catch (Throwable e) {

        }
    }

    private static void run() {

        runStartTime = System.currentTimeMillis();

        while (true) {

            // checkRunCount.getAndIncrement();

            try {

                long max = JvmUtil.maxMemory();
                long heapUsed = JvmUtil.heapUsed();

                if (heapUsed < (max * HEAP_USE_MAX)) {

                    String key = genKey();
                    String value = genValue();
                    datamap.put(key, value);

                    continue;
                }

                long dataMapSize = datamap.size();

                clearRunCount.getAndIncrement();
                long start = System.currentTimeMillis();
                datamap.clear();
                long end = System.currentTimeMillis();
                long time = end - start;
                clearRunTotalTime.addAndGet(time);
                lastClearRunTime = time;
                lastClearRunTimeAt = LocalDateTime.now().toString();

                long dataMapSizeAfterClear = datamap.size();

                lastClearInfo = dataMapSize + "," + dataMapSizeAfterClear;
                clearCountTotal.addAndGet(dataMapSize - dataMapSizeAfterClear);

                System.gc();
                // 20211206
                // doSleep(30);

            } catch (Throwable e) {
                errorCount.getAndIncrement();
                lastError = e + "";

            }

        }

    }

    public final static long tps() {
        if (runStartTime <= 0) {
            return 0;
        }
        long time = System.currentTimeMillis() - runStartTime;
        if (time <= 0) {
            return 0;
        }
        long tps = totalKeyCount.get() * 1000 / time;
        return tps;
    }

}
